package github.sf.fw.tools.spi;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * spi factory
 *
 * @author zhoup
 */
public class SpiFactory {
    private final static Map<Class<?>, ClassFactory<?>> FACTORIES = new ConcurrentHashMap<>();
    private final static Object LOCK = new Object();

    private SpiFactory() {
    }


    public static <T> ClassFactory<T> getClassFactory(Class<T> keyClass) {
        return getClassFactory(keyClass, new DefaultClassNameGenerator(), Thread.currentThread().getContextClassLoader());
    }

    public static <T> ClassFactory<T> getClassFactory(Class<T> keyClass, ClassLoader classLoader) {
        return getClassFactory(keyClass, new DefaultClassNameGenerator(), classLoader);
    }

    public static <T> ClassFactory<T> getClassFactory(Class<T> keyClass, ClassNameGenerator classNameGenerator) {
        return getClassFactory(keyClass, classNameGenerator, Thread.currentThread().getContextClassLoader());
    }

    @SuppressWarnings(value = {"unchecked"})
    public static <T> ClassFactory<T> getClassFactory(Class<T> keyClass, ClassNameGenerator classNameGenerator, ClassLoader classLoader) {
        ClassFactory<T> classFactory = (ClassFactory<T>) FACTORIES.get(keyClass);
        if (classFactory == null) {
            synchronized (LOCK) {
                ClassFactory<T> newClassFactory = new ClassFactory<>(classNameGenerator, keyClass, classLoader);
                FACTORIES.put(keyClass, newClassFactory);
                return newClassFactory;
            }
        }
        return classFactory;
    }

    /**
     * 返回具体的实现类对象实例
     *
     * @param clazz         顶层的抽象接口
     * @param implClassName 抽象接口某个具体实现类的名称
     * @param <T>           具体实现类的类型
     * @return 具体实现类的对象实例
     */
    public static <T> T getObject(Class<T> clazz, String implClassName) {
        ClassFactory<T> classFactory = getClassFactory(clazz);
        return classFactory.getNewComponent(implClassName);
    }

    /**
     * 返回具体的实现类对象实例(缓存中的对象实列)
     *
     * @param clazz         顶层的抽象接口
     * @param implClassName 抽象接口某个具体实现类的名称
     * @param <T>           具体实现类的类型
     * @return 具体实现类的对象实例
     */
    public static <T> T getObjectWithCache(Class<T> clazz, String implClassName) {
        ClassFactory<T> classFactory = getClassFactory(clazz);
        return classFactory.getComponentWithCache(implClassName);
    }
}
